package org.springblade.modules.mes.opcua.server;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.modules.mes.base.entity.*;
import org.springblade.modules.mes.base.service.ILmsProductionOrderService;
import org.springblade.modules.mes.base.service.IStationAssemblyService;
import org.springblade.modules.mes.opcua.constant.OpcUaCache;
import org.springblade.modules.mes.opcua.constant.OpcUaError;
import org.springblade.modules.mes.opcua.constant.OpcUaKey;
import org.springblade.modules.mes.opcua.itf.OpcUa;
import org.springblade.modules.mes.opcua.vo.OpcUaVO;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 产品生产相关
 */
@Service
@AllArgsConstructor
@Slf4j
public class RequestService {

	private final IStationAssemblyService stationAssemblyService;

	private final ILmsProductionOrderService lmsProductionOrderService;

	private final ToolService toolService;

	/**
	 * 申请总成流水号
	 */
	@DSTransactional
	@DS("master")
	public boolean assemblyBarcodeApply(OpcUaVO ctx, String newBarCode) throws Exception {
		//查询站位
		ProduceSite site = OpcUaCache.getBySiteCode(ctx.getSiteCode());
		if (site == null) {
			toolService.plcMessage(ctx, OpcUaError.E01000);
			OpcUa.getInstance().writeValue(ctx, ctx.getPosition(), OpcUaKey.orderStatus, (short) 3);
			return false;
		}

		//判断工位是否已经上架其他产品，如果上架只能申请统一组下的其他配方
		String prodGroupNo = null;
		List<StationAssembly> stationAssemblys = stationAssemblyService.list(new QueryWrapper<StationAssembly>().lambda()
			.eq(StationAssembly::getStationCode, site.getStationCode())
			.eq(StationAssembly::getSiteCode, site.getSiteCode())
			.eq(StationAssembly::getStatus, 0)
			.orderByAsc(StationAssembly::getCreateTime));
		if (stationAssemblys != null && stationAssemblys.size() > 0) {
			StationAssembly a = stationAssemblys.get(0);
			PrdInfo prd = OpcUaCache.getByProdCode(a.getAssemblyNo());
			prodGroupNo = prd.getMaterialGroupNo();
			for (StationAssembly as : stationAssemblys) {
				if (as.getPosition().equals(ctx.getPosition())) {
					toolService.plcMessage(ctx, OpcUaError.E11001);
					OpcUa.getInstance().writeValue(ctx, ctx.getPosition(), OpcUaKey.orderStatus, (short) 3);
					return false;
				}
			}
		}

		//本工序是第一工序的所有产品编码
		//查询这个位置，对应物料的配方
		//就是符合条件的配方
		List<PrdBom> boms = toolService.findBom(site, prodGroupNo, ctx);
		if (boms == null || boms.size() == 0) {
			toolService.plcMessage(ctx, OpcUaError.E01001);
			OpcUa.getInstance().writeValue(ctx, ctx.getPosition(), OpcUaKey.orderStatus, (short) 3);
			return false;
		}
		Set<String> procCodeList = new HashSet<>(boms.size());
		boms.forEach(d -> {
			procCodeList.add(d.getMaterialNo());
		});


		//查询符合条件的所有订单
		LMSDetail order = lmsProductionOrderService.getOne(new QueryWrapper<LMSDetail>()
			.lambda()
			.in(LMSDetail::getMatCode, procCodeList)
			.eq(LMSDetail::getStatus, "0")
			//计划是已下方，或下方中
			.exists("select * from prj_produce_plan tt where tt.prod_code = prj_lms_order_detail.mat_code and tt.status in(1,2)")
			.orderByAsc(LMSDetail::getProductTime, LMSDetail::getSequence).last("limit 1"));
		if (ObjectUtil.isEmpty(order)) {
			toolService.plcMessage(ctx, OpcUaError.E01002);
			OpcUa.getInstance().writeValue(ctx, ctx.getPosition(), OpcUaKey.orderStatus, (short) 3);
			return false;
		}

		//获取产品信息
		PrdInfo prdInfo = OpcUaCache.getByProdCode(order.getMatCode());
		if (ObjectUtil.isEmpty(prdInfo)) {
			toolService.plcMessage(ctx, OpcUaError.E01003);
			OpcUa.getInstance().writeValue(ctx, ctx.getPosition(), OpcUaKey.orderStatus, (short) 3);
			return false;
		}

		//订单申请完成
		order.setStatus(1);
		toolService.updateOrderStatus(order.getBarCode(), 1, newBarCode);
		if (newBarCode != null && newBarCode.length() > 0) {
			order.setBarCode(newBarCode);
		}
		OpcUa.getInstance().writeValue(ctx, ctx.getPosition(), OpcUaKey.orderStatus, (short) 2);

		//上架
		//主bom
		PrdBom mainBom = OpcUaCache.getBomByMatCode(order.getMatCode());
		//工位与总成流水号绑定
		StationAssembly stationAssembly = new StationAssembly();
		stationAssembly.setCreateTime(new Date());
		stationAssembly.setStationCode(site.getStationCode());
		stationAssembly.setSiteCode(site.getSiteCode());
		stationAssembly.setAssemblyBarcode(order.getBarCode());
		stationAssembly.setAssemblyNo(prdInfo.getMaterialNo());
		stationAssembly.setPackageBarcode(order.getBarCode());
		stationAssembly.setPrintNo(order.getBarCode());
		stationAssembly.setPosition(mainBom.getPosition());
		stationAssembly.setStatus(0);
		if (stationAssemblyService.save(stationAssembly)) {
			//上架后赋值PLC
			toolService.plcAssemblyOnScan(ctx, stationAssembly.getPosition(), order);
			//校验当前工位是否扫描完成
			toolService.scanComplete(stationAssembly, order, ctx);
			return true;
		} else {
			toolService.plcMessage(ctx, OpcUaError.E01005);
			toolService.plcScanStatus(ctx, (short) 3);
			return false;
		}
	}
}
